

  require "uri" 
  require "net/http" 

  module HttpToYaml
    class TooManyRedirects < StandardError; end

    BACKEND = 'http://localhost:4000'

    protected

    def get(uri, redirection_limit = 10)
      uri = URI.parse("#{BACKEND}#{uri}")
      response = Net::HTTP.start(uri.host, uri.port) do |http|
        http.get(uri.path, {'Accept' => 'text/yaml'})
      end
      handle_or_decode_response(response, :redirection_limit => redirection_limit)
    end

    def post(uri, params = {})
      uri = URI.parse("#{BACKEND}#{uri}")
      response = Net::HTTP.start(uri.host, uri.port) do |http|
        request = Net::HTTP::Post.new(uri.path)
        request['Accept'] = 'text/yaml'
        request.set_form_data(params)
        http.request(request)
      end
      handle_or_decode_response(response)
    end

    def put(uri, params = {})
      post uri, params.merge(:_method => 'put')    
    end

    def delete(uri, params = {})
      post uri, params.merge(:_method => 'delete')
    end

    def handle_or_decode_response(response, options = {})
      case response
      when Net::HTTPSuccess
        YAML.load(response.body)
      when Net::HTTPRedirection
        limit = options[:redirection_limit] || 10
        raise TooManyRedirects if limit == 1
        get response['Location'], limit - 1
      end
    end
  end
  class ShoesPaste < Shoes
    include HttpToYaml

    url '/', :index
    url '/new', :new_paste
    url '/(\d+)', :show_paste

    def index
      pastes = get "/pastes" 

      stack :margin => 20 do    
        title "Shoes Pastebin" 

        pastes.sort_by{|p| p[:created_at]}.each do |paste|
          para link(paste[:title], :click => "/#{paste[:id]}")
        end

        para link('New paste', :click => "/new")
      end
    end

    def show_paste(id)
      paste = get "/pastes/#{id}" 
      stack :margin => 20 do
        title paste[:title]
        para paste[:text], :font => 'Monospace 12px'
        button "delete" do
          if confirm("Are you sure you want to delete this paste?")
            delete "/pastes/#{paste[:id]}" 
            visit "/" 
          end
        end
        view_all_link
      end
    end

    def new_paste
      stack :margin => 20 do
        title "New paste" 
        flow(:margin_top => 20) { caption "Title: "; @title = edit_line }
        @text = edit_box :margin_top => 20, :width => 400, :height => 200

        button("Paste!", :margin => 5) do
          paste = post '/pastes', :title => @title.text, :text => @text.text
          visit "/#{paste[:id]}" 
        end

        view_all_link
      end
    end

    protected

    def view_all_link
      para(link('View all pastes', :click => '/'), :margin_top => 20)
    end

  end

  Shoes.app :title => 'Shoes Pastebin', :width => 640, :height => 400